package sk.naive.talker.adapter;

import java.util.regex.*;
import java.util.*;

/**
 * Adapter message processor.
 * <p>
 * Searches for "tags" in the message text and let tag processor to process them.
 * Tag's form is <tt>&lt;tag(optional-parameters)&gt;</tt>. Instance of processor have
 * its own map for tag processors. Tag processors should be registered in order to
 * process appropriate message tag.
 * <p>
 * Implementation of the <tt>process</tt> method is thread safe and can be
 * called recursively. State is stored in message processing context object.
 *
 * @see MessageProcessingContext
 * @see TagProcessor
 * @author <a href="mailto:virgo@naive.deepblue.sk">Richard "Virgo" Richter</a>
 * @version $Revision: 1.12 $ $Date: 2005/01/06 16:27:05 $
 */
public class DefaultMessageProcessor
	implements sk.naive.talker.adapter.MessageProcessor
{
	private static final Pattern tagPattern = Pattern.compile("<(.+?)(?:\\((.*?)\\))?>");
	private AbstractUser user;

	public DefaultMessageProcessor(AbstractUser user) {
		this.user = user;
	}

	private Map tagProcessors = new HashMap();

	public String process(String msg) throws TagProcessorException {
		if (msg == null) {
			return null;
		}
		MessageProcessingContext ctx = new MessageProcessingContext(user);
		Matcher m = tagPattern.matcher(msg);
		int lastEnd = 0;
		while (m.find()) {
			TagProcessor tp = (TagProcessor) tagProcessors.get(m.group(1));
			if (tp == null) {
				continue;
			}
			ctx.append(msg.substring(lastEnd, m.start()));
			String tmp = tp.process(ctx, m.group(2));
			if (tmp != null) {
				ctx.append(tmp);
			}
			lastEnd = m.end();
			if (ctx.isProcessingInterrupted()) {
				break;
			}
		}
		ctx.append(msg.substring(lastEnd));
		return ctx.result();
	}

	public void registerTagProcessor(String tag, TagProcessor processor) {
		tagProcessors.put(tag, processor);
	}
}
